#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2016 lizongzhe 
#
# Distributed under terms of the MIT license.
import collections
import json
import random
import logging
import sys
import gevent
from gevent.timeout import Timeout
from proxy_manager.exceptions import ProxyEmpty, ProxyCheckError
import random
import time

logger = logging.getLogger(__name__)

ProxyHostT = collections.namedtuple('ProxyHost', ['ip', 'port', 'scheme', 'auth'])

def to_dict(proxy_host):
    data = {}
    data['ip'] = proxy_host.ip
    data['port'] = proxy_host.port
    data['scheme'] = proxy_host.scheme
    data['auth'] = proxy_host.auth
    return data

def to_proxyhost(proxy_dict):
    return ProxyHost(**proxy_dict)

def ProxyHost(ip, port, scheme, auth=None):
    return ProxyHostT(ip, port, scheme, auth)


def encode_proxy_host(proxy_host):
    return json.dumps(proxy_host)

def decode_proxy_host(proxy_host_code):
    return ProxyHost(*json.loads(proxy_host_code))

class ProxyManager(object):
    in_use_proxy = {}
    proxy_list = None
    proxy_storage = []

    def __init__(self, resources=[], checkers=[], logger=logger):
        self.logger = logger
        self.proxy_resources = resources
        self.checkers = checkers
        self.refresh_proxies()

    def crawl_proxies(self, focus=False):
        self.logger.debug('start crawl proxies')
        random.shuffle(self.proxy_resources)
        for proxy_resource in self.proxy_resources:
            try:

                self.logger.debug('start proxy resource {}'.format(proxy_resource))

                with gevent.Timeout(5):
                    proxy_list = proxy_resource.get_proxies()
    
                while proxy_list:
                    if self.proxy_storage:
                        proxy = self.proxy_storage.pop()
                    else:
                        proxy = proxy_list.pop()
                    yield proxy

            except Exception as e:
                print e
                self.logger.debug('error on {}'.format(proxy_resource))
            except Timeout as e:
                print 'timeout'
                self.logger.debug('timeout on {}'.format(proxy_resource))

    def health_check(self, proxy_host):
        for checker in self.checkers:
            try:
                checker(proxy_host)
            except Exception as e:
                self.logger.debug("error:{} - {} is not with {}".format(e, proxy_host, checker))
                raise ProxyCheckError()

    def reuse_proxy(self, proxy):
        self.proxy_storage.append(proxy)

    def refresh_proxies(self):
        self.proxy_list = self.crawl_proxies()

    def get_proxy(self):
        try:
            proxy = self.proxy_list.next()
            self.health_check(proxy)
        except StopIteration:
            self.refresh_proxies()
            time.sleep(random.randint(30, 60))
            proxy = self.get_proxy()

        return proxy
